﻿using FRMS.DAL;
using FRMS.Model;
using Newtonsoft.Json;
using Org.BouncyCastle.Security;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace FRMS.BUS.ServerPlatform
{
    public class FRMSServer
    {
        public Dictionary<string, Socket> OnlineDic { get { return dict; } }
        private static object locker = new object();
        public FRMSServer()
        {
            ServerInit();
        }
        private void ServerInit()
        {
            try
            {
                //int port = Convert.ToInt32(CommVars.Configuration.GetSection("Port").Value);
                int port = Convert.ToInt32(AppSettingsHelper.Configuration["Port"]);
                string localip = GetLocalIp();
                StartServer(localip, port);
                //LogHelper.Log("平台服务建立成功");
                //StartServer("192.168.8.159", 20001);
            }
            catch (Exception ex)
            {
                //LogHelper.Log(ex.ToString());
            }
        }

        public string GetLocalIp()
        {
            var addressList = System.Net.Dns.GetHostEntry(System.Net.Dns.GetHostName()).AddressList;
            var ip = addressList.FirstOrDefault(address => address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)?.ToString();
            return ip;
        }

        Dictionary<string, Socket> dict = new Dictionary<string, Socket>();
        Dictionary<int, int> result_dict = new Dictionary<int, int>();
        public Dictionary<string, Socket> devid_dict = new Dictionary<string, Socket>();
        Thread threadWatch = null; // 负责监听客户端连接请求的 线程；
        Socket socketWatch = null;
        int packcount = 1;

        public void StartServer(string ip, int port)
        {
            // 创建负责监听的套接字，注意其中的参数；
            socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            // 获得文本框中的IP对象；
            IPAddress address = IPAddress.Parse(ip);
            // 创建包含ip和端口号的网络节点对象；
            IPEndPoint endPoint = new IPEndPoint(address, port);
            try
            {
                // 将负责监听的套接字绑定到唯一的ip和端口上；
                socketWatch.Bind(endPoint);
            }
            catch (SocketException se)
            {
                return;
            }
            // 设置监听队列的长度；
            socketWatch.Listen(10);
            // 创建负责监听的线程；
            threadWatch = new Thread(WatchConnecting);
            threadWatch.IsBackground = true;
            threadWatch.Start();

        }

        /// <summary>
        /// 监听客户端请求的方法；
        /// </summary>
        void WatchConnecting()
        {
            while (true)  // 持续不断的监听客户端的连接请求；
            {
                // 开始监听客户端连接请求，Accept方法会阻断当前的线程；
                Socket sokConnection = socketWatch.Accept(); // 一旦监听到一个客户端的请求，就返回一个与该客户端通信的 套接字；
                // 想列表控件中添加客户端的IP信息；
                //dict.Add(sokConnection.RemoteEndPoint.ToString(), sokConnection);
                sokConnection.ReceiveTimeout = 60000;
                Thread thr = new Thread(RecMsg);
                thr.IsBackground = true;
                thr.Start(sokConnection);
            }
        }

        void RecMsg(object sokConnectionparn)
        {
            Socket sokClient = sokConnectionparn as Socket;
            while (true)
            {
                // 定义一个2M的缓存区；
                byte[] arrMsgRec = new byte[1024 * 1024 * 2];
                // 将接受到的数据存入到输入  arrMsgRec中；
                int length = -1;
                try
                {

                    length = sokClient.Receive(arrMsgRec); // 接收数据，并返回数据的长度；
                    if (sokClient.Connected)
                    {
                        if (length > 0)
                        {
                            // string strMsg = Encoding.UTF8.GetString(arrMsgRec, 0, length);// 将接受到的字节数据转化成字符串；
                            string devid;
                            string replay = DataHandling(arrMsgRec, length, out devid);
                            if (!string.IsNullOrEmpty(devid))
                            {
                                if (devid_dict.ContainsKey(devid))
                                {
                                    devid_dict.Remove(devid);
                                }
                                devid_dict.Add(devid, sokClient);
                                /* RecordDAL da = new RecordDAL();
                                 da.InsertDeviceRecord(devid, "在线");*/
                            }
                            if (!string.IsNullOrEmpty(replay))
                            {
                                RepalyClient(sokClient, replay);
                            }
                        }
                    }
                    else
                    {
                        ClearDevDic(sokClient);
                    }

                }
                catch (SocketException se)
                {
                    // 从 通信套接字 集合中删除被中断连接的通信套接字；
                    //dict.Remove(sokClient.RemoteEndPoint.ToString());
                    ClearDevDic(sokClient);
                    break;
                }
            }
        }

        public void ClearDevDic(Socket socket)
        {
            foreach (var item in devid_dict)
            {
                if (item.Value.RemoteEndPoint == socket.RemoteEndPoint)
                {
                    devid_dict.Remove(item.Key);
                    /* RecordDAL da = new RecordDAL();
                     da.InsertDeviceRecord(item.Key, "离线");*/
                }
            }
        }

        public string DataHandling(byte[] arrMsgRec, int length, out string devid)
        {
            try
            {
                byte[] data = AnalysisData(arrMsgRec, length);
                Message message = AnalysisType(data);
                string replay = string.Empty;
                devid = string.Empty;
                if (message != null)
                {
                    if (message.Data != null)
                    {
                        string msg = message.Data[0].ToString();
                        ReplayMsg replayMsg = new ReplayMsg();
                        if (message.Command == "COM_DEV_REGISTER")
                        {
                            replayMsg = Register(msg, out devid);
                        }

                        else if (message.Command == "COM_UPLOAD_SUB_DEV")
                        {
                            replayMsg.Command = "COM_UPLOAD_SUB_DEV";
                            replayMsg.Result = 0;
                        }
                        else if (message.Command == "FAC_UPLOAD_BA_STATUS")
                        {
                            replayMsg.Command = "FAC_UPLOAD_BA_STATUS";
                            replayMsg.Result = 0;
                        }
                        else if (message.Command == "FAC_ELEVATOR_RECORD")
                        {
                            replayMsg.Command = "FAC_ELEVATOR_RECORD";
                            replayMsg.Result = 0;
                            /* Incident incident = JsonConvert.DeserializeObject<Incident>(message.Data[0].ToString());
                             RecordDAL da = new RecordDAL();
                             da.InsertLadderRecord(incident, "成功");*/
                        }

                        replay = StringToHex(JsonConvert.SerializeObject(replayMsg));
                        replay = ProcessSendMsg(data, replay);
                    }
                    else
                    {
                        if (message.Command == "COM_LOAD_CERTIFICATE" || message.Command == "COM_DELETE_CERTIFICATE" || message.Command == "COM_DELETE_CERTIFICATE_IN_BATCH")
                        {
                            if (data[44] == 0 && ByteArrayToString(data.Skip(24).Take(20).ToArray()) == "00000000000000000000")
                            {
                                byte[] data1 = (byte[])data.Skip(57).Take(data.Length - 57).ToArray();
                                string result = Encoding.UTF8.GetString(data1, 0, data1.Length);
                                ReplayMsg revMsg = JsonConvert.DeserializeObject<ReplayMsg>(result);
                                int datanum = BytesToInt32(data.Skip(45).Take(4).ToArray());
                                if (result_dict.ContainsKey(datanum))
                                {
                                    result_dict.Remove(datanum);
                                }
                                result_dict.Add(datanum, revMsg.Result);
                            }
                        }
                        else if (message.Command == "COM_HEARTBEAT")
                        {
                            ReplayMsg replayMsg = new ReplayMsg();
                            replayMsg.Command = "COM_HEARTBEAT";
                            replayMsg.Result = 0;

                            replay = StringToHex(JsonConvert.SerializeObject(replayMsg));
                            replay = ProcessSendMsg(data, replay);
                        }
                    }
                }
                return replay;
            }
            catch (Exception ex)
            {
                devid = string.Empty;
                return "";
            }
        }

        public string ProcessSendMsg(byte[] arrMsgRec, string data)
        {
            byte[] buffer = new byte[20];
            for (int i = 0; i < 20; i++)
            {
                buffer[i] = arrMsgRec[4 + i];
            }
            string datazs = string.Format("{0} {1} {2} {3}", arrMsgRec[45].ToString("X").PadLeft(2, '0'), arrMsgRec[46].ToString("X").PadLeft(2, '0'), arrMsgRec[47].ToString("X").PadLeft(2, '0'), arrMsgRec[48].ToString("X").PadLeft(2, '0'));
            string strCmd = data;
            int num = data.Split(' ').Length;
            string datalength = IntToHex(num).PadLeft(8, '0').ToUpper();
            string length1 = datalength.Substring(0, 2) + " " + datalength.Substring(2, 2) + " " + datalength.Substring(4, 2) + " " + datalength.Substring(6, 2);
            string crc = CRCCalc(strCmd);
            strCmd = "48 44 58 4D " + StringToHex("00000000000000000000") + " " + ToHexs(buffer) + " 01 " + datazs + " " + length1 + " 00 00 " + crc + " " + strCmd;

            return strCmd;
        }

        public ReplayMsg Register(string data, out string deviceid)
        {
            ReplayMsg repaly = new ReplayMsg();
            repaly.Command = "COM_DEV_REGISTER";
            RegisterInfo registerMsg = GetRegister(data);
            DeviceDAL da = new DeviceDAL();
            int exist = da.CheckDev(registerMsg.deviceID);
            if (exist > 0)
            {
                if (da.UpdateDevice(registerMsg))
                {
                    repaly.Result = 0;
                    deviceid = registerMsg.deviceID;
                }
                else
                {
                    repaly.Result = 1;
                    deviceid = "";
                }
            }
            else
            {
                repaly.Result = 1;
                deviceid = "";
            }

            return repaly;
        }

        public RegisterInfo GetRegister(string data)
        {
            RegisterInfo registerMsg;
            try
            {
                registerMsg = JsonConvert.DeserializeObject<RegisterInfo>(data);
            }
            catch
            {
                return null;
            }
            return registerMsg;
        }

        /// <summary>
        /// 回复客户端消息
        /// </summary>
        public bool RepalyClient(Socket socket, string msg)
        {
            try
            {
                socket.Send(HexStringToByteArray(msg));
                return true;
            }
            catch
            {
                return false;
            }
        }

        /// <summary>
        /// 校验数据
        /// </summary>
        public byte[] AnalysisData(byte[] buffer, int length)
        {
            for (int i = 0; i < length; i++)
            {
                if (buffer[i] == 0x48 && buffer[i + 1] == 0x44 && buffer[i + 2] == 0x58 && buffer[i + 3] == 0x4D)
                {
                    byte[] buf = new byte[4];
                    buf[0] = buffer[i + 49];
                    buf[1] = buffer[i + 50];
                    buf[2] = buffer[i + 51];
                    buf[3] = buffer[i + 52];
                    int count = BytesToInt32(buf);
                    if (count > 0)
                    {
                        byte[] analysisdata = new byte[count];
                        for (int k = 0; k < count; k++)
                        {
                            analysisdata[k] = buffer[i + k + 57];
                        }
                        byte[] crcbuffer = new byte[2];
                        crcbuffer[0] = buffer[i + 55];
                        crcbuffer[1] = buffer[i + 56];
                        string analysiscrc = CRCCalc(analysisdata);
                        string datacrc = ToHexs(crcbuffer);
                        if (analysiscrc == datacrc)
                        {
                            return buffer.Skip(i).Take(57 + count).ToArray();
                        }
                        else
                        {
                            return null;
                        }
                    }
                    else
                    {
                        return null;
                    }
                }
                else
                {
                    continue;
                }
            }
            return null;
        }
        public string ToHexs(byte[] data)
        {
            if (data.Length <= 0) return "";
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < data.Length; i++)
            {
                sb.Append(data[i].ToString("X2"));
                sb.Append(" ");
            }
            string str = sb.ToString();
            return str.Substring(0, str.Length - 1);
        }
        public string StringToHex(string strEncode)
        {
            string strReturn = "";
            foreach (short shortx in strEncode.ToCharArray())
            {
                strReturn += shortx.ToString("X2") + " ";
            }
            strReturn = strReturn.TrimEnd(' ').ToUpper();
            return strReturn;
        }

        public string IntToHex(int num)
        {
            string result = "";
            result = Convert.ToString(num, 16).ToUpper();
            return result;
        }

        /// <summary>
        /// 字符串转byte
        /// </summary>
        public byte[] HexStringToByteArray(string s)
        {
            s = s.Replace(" ", "");
            byte[] buffer = new byte[s.Length / 2];
            for (int i = 0; i < s.Length; i += 2)
                buffer[i / 2] = (byte)Convert.ToByte(s.Substring(i, 2), 16);
            return buffer;
        }

        public string ByteArrayToString(byte[] byteArray)
        {
            string str = Encoding.ASCII.GetString(byteArray, 0, byteArray.Length);
            return str.ToUpper();
        }

        private int BytesToInt32(byte[] bs)
        {
            try
            {
                if (bs == null || bs.Length != 4)
                {
                    return 0;
                }
                //获取最高八位
                uint num1 = 0;
                num1 = (uint)(Convert.ToInt32(num1) ^ (int)bs[0]);
                num1 = num1 << 24;
                //获取第二高八位
                uint num2 = 0;
                num2 = (uint)(Convert.ToInt32(num2) ^ (int)bs[1]);
                num2 = num2 << 16;
                //获取第二低八位
                uint num3 = 0;
                num3 = (uint)(Convert.ToInt32(num3) ^ (int)bs[2]);
                num3 = num3 << 8;
                //获取低八位
                uint num4 = 0;
                num4 = (uint)(Convert.ToInt32(num4) ^ (int)bs[3]);
                return Convert.ToInt32(num1 ^ num2 ^ num3 ^ num4);
            }
            catch
            {
                return 0;
            }
        }

        /// <summary>
        /// CRC校验
        /// </summary>
        public string CRCCalc(string data)
        {
            string[] datas = data.Split(' ');
            List<byte> bytedata = new List<byte>();

            foreach (string str in datas)
            {
                bytedata.Add(byte.Parse(str, System.Globalization.NumberStyles.AllowHexSpecifier));
            }
            byte[] crcbuf = bytedata.ToArray();
            //计算并填写CRC校验码
            int crc = 0xffff;
            int len = crcbuf.Length;

            for (int j = 0; j < len; j++)
            {
                crc = ((crc >> 8) | (crc << 8)) & 0xffff;
                crc ^= (crcbuf[j] & 0xff);
                crc ^= ((crc & 0xff) >> 4);
                crc ^= (crc << 12) & 0xffff;
                crc ^= ((crc & 0xff) << 5) & 0xffff;
            }
            crc = crc & 0xffff;

            string[] redata = new string[2];
            redata[1] = Convert.ToString((byte)((crc >> 8) & 0xff), 16);
            redata[0] = Convert.ToString((byte)((crc & 0xff)), 16);
            string a = redata[1].ToString().PadLeft(2, '0') + " " + redata[0].ToString().PadLeft(2, '0');
            return a.ToUpper();
        }

        public string CRCCalc(byte[] crcbuf)
        {
            //计算并填写CRC校验码
            int crc = 0xffff;
            int len = crcbuf.Length;

            for (int j = 0; j < len; j++)
            {
                crc = ((crc >> 8) | (crc << 8)) & 0xffff;
                crc ^= (crcbuf[j] & 0xff);
                crc ^= ((crc & 0xff) >> 4);
                crc ^= (crc << 12) & 0xffff;
                crc ^= ((crc & 0xff) << 5) & 0xffff;
            }
            crc = crc & 0xffff;

            string[] redata = new string[2];
            redata[1] = Convert.ToString((byte)((crc >> 8) & 0xff), 16);
            redata[0] = Convert.ToString((byte)((crc & 0xff)), 16);
            string a = redata[1].ToString().PadLeft(2, '0') + " " + redata[0].ToString().PadLeft(2, '0');
            return a.ToUpper();
        }

        /// <summary>
        /// 解析数据类型
        /// </summary>
        public Message AnalysisType(byte[] data)
        {
            Message message;
            try
            {
                byte[] data1 = (byte[])data.Skip(57).Take(data.Length - 57).ToArray();
                string result = string.Empty;
                result = Encoding.UTF8.GetString(data1, 0, data1.Length);
                message = JsonConvert.DeserializeObject<Message>(result);
            }
            catch (Exception ex)
            {
                return null;
            }
            return message;
        }

        public ReplayMsg AnalysisReplay(byte[] data)
        {
            ReplayMsg message;
            try
            {
                byte[] data1 = (byte[])data.Skip(57).Take(data.Length - 57).ToArray();
                string result = string.Empty;
                result = Encoding.UTF8.GetString(data1, 0, data1.Length);
                message = JsonConvert.DeserializeObject<ReplayMsg>(result);
            }
            catch (Exception ex)
            {
                return null;
            }
            return message;
        }

        public int GetPackNum()
        {
            lock (locker)
            {
                int num = packcount;

                if (num == 2147483647)
                {
                    packcount = 1;
                }
                else
                {
                    packcount++;
                }
                return num;
            }
        }

        public string SendMsgToDev(byte[] buffer, string deviceid)
        {
            ResponseMessage message = new ResponseMessage();
            Socket socket;
            try
            {
                if (devid_dict.TryGetValue(deviceid, out socket))
                {
                    socket.Send(buffer);
                    return "success";
                }
                else
                {
                    return "下发失败，该设备未注册";
                }
            }
            catch
            {
                return "下发失败";
            }
        }

        public bool Replay(int datamun)
        {
            try
            {
                int i = 0;
                while (i < 3)
                {
                    if (result_dict.ContainsKey(datamun))
                    {
                        int result;
                        result_dict.TryGetValue(datamun, out result);
                        if (result == 0)
                        {
                            return true;
                        }
                        else
                        {
                            return false;
                        }
                    }
                    i++;
                    Thread.Sleep(300);
                }
                return false;
            }
            catch
            {
                return false;
            }
        }

    }

}
